/*
 * PBBLogging.java
 *
 * Created on July 15, 2007, 11:17 AM
 *
 *Copyright 2007-2008 Jon W Huss III

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
 *
 */

package proteinboxbot;

import proteinboxbot.*;
import java.io.*;
import java.util.*;
import java.text.DateFormat;
import org.apache.commons.lang.StringEscapeUtils;




/**
 *
 * @author Jon Huss
 */
public class PBBLogging {
    
    public static final String SUMMARY = "Summary.html";
    public static final String ERROR = "Error.html";
    public static final String CREATED = "Created.html";
    public static final String UPDATED = "Updated.html";
    public static final String SKIPPED = "Skipped.html";
    public static final String SYSTEM = "System.html";
    public static final String REDIRECTED = "Redirect.html";
    
    public enum logs {
        SU {
            String filename() { return SUMMARY; };
            //File file() { return fSummary; };
            String text() {return "Summary";}
            int count = 0;
            void setPCount(int x) {
                count = x;
            }
            int getPCount() {
                return count;
            }
        },
        ER { String filename() { return ERROR;   };
        //File file() { return fError; };
        String text() {return "Errors";}
        int count = 0;
        void setPCount(int x) {
            count = x;
        }
        int getPCount() {
            return count;
        }
        },
        CR { String filename() { return CREATED; };
        //File file() { return fCreated; };
        String text() {return "Created Protein Pages";}
        int count = 0;
        void setPCount(int x) {
            count = x;
        }
        int getPCount() {
            return count;
        }
        },
        UP { String filename() { return UPDATED; };
        //File file() { return fUpdated; };
        String text() {return "Updated Protein Pages";}
        int count = 0;
        void setPCount(int x) {
            count = x;
        }
        int getPCount() {
            return count;
        }
        },
        SK { String filename() { return SKIPPED; };
        String text() {return "Skipped Proteins";}
        int count = 0;
        void setPCount(int x) {
            count = x;
        }
        int getPCount() {
            return count;
        }
        },
        RD { String filename() { return REDIRECTED; };
        String text() {return "Redirected Proteins";}
        int count = 0;
        void setPCount(int x) {
            count = x;
        }
        int getPCount() {
            return count;
        }
        },
        SY { String filename() { return SYSTEM; };
        String text() {return "System Messages";}
        int count = 0;
        void setPCount(int x) {
            count = x;
        }
        int getPCount() {
            return count;
        }
        };
        
        abstract String filename();
        //abstract File file();
        abstract String text();
        abstract void setPCount(int x);
        abstract int getPCount();
    };
    
    
    //The hashtable maps the protein to the log entries
    //the entries are stored in vectors of Entry
    
    private TreeMap<String,Vector> logEntries;
    
    //used to track what happens with each protein.  Does the protein create a new page?
    //Does is get skipped because of an Error or because of No Bots?  that kind of stuff.
    public enum pStatus {
        Skip_no_bots{
            String text() {return "Manual Inspection (NO BOTS tag)";}
            int count = 0;
            void setPCount(int x) {
                count = x;
            }
            int getPCount() {
                return count;
            }
        },
        Skip_error{
            String text() {return "Manual Inspection (Unknown Error)";}
            int count = 0;
            void setPCount(int x) {
                count = x;
            }
            int getPCount() {
                return count;
            }
        },
        Skip_tag_error{
            String text() {return "Manual Inspection (Parsing Error)";}
            int count = 0;
            void setPCount(int x) {
                count = x;
            }
            int getPCount() {
                return count;
            }
        },
        Skip_no_update{
            String text() {return "Manual Inspection (Updates Off)";}
            int count = 0;
            void setPCount(int x) {
                count = x;
            }
            int getPCount() {
                return count;
            }
        },
        Skip_manual_insp{
            String text() {return "Manual Inspection (Control Box)";}
            int count = 0;
            void setPCount(int x) {
                count = x;
            }
            int getPCount() {
                return count;
            }
        },
        created{
            String text() {return "Created";}
            int count = 0;
            void setPCount(int x) {
                count = x;
            }
            int getPCount() {
                return count;
            }
        },
        unresolved{
            String text() {return "Unresolved Status";}
            int count = 0;
            void setPCount(int x) {
                count = x;
            }
            int getPCount() {
                return count;
            }
        },
        Skip_amb_page{
            String text() {return "Manual Inspection (Page not found)";}
            int count = 0;
            void setPCount(int x) {
                count = x;
            }
            int getPCount() {
                return count;
            }
        },
        updated_warning{
            String text() {return "Updated with Warning";}
            int count = 0;
            void setPCount(int x) {
                count = x;
            }
            int getPCount() {
                return count;
            }
        },
        updated{
            String text() {return "Updated";}
            int count = 0;
            void setPCount(int x) {
                count = x;
            }
            int getPCount() {
                return count;
            }
        };
        
        abstract String text();
        abstract void setPCount(int x);
        abstract int getPCount();
    }
    //8,15,17,20,10
    public Hashtable<String,pStatus> glblProteinStatus;
    
    public Hashtable<String,String> glblProteinTargetPages;
    
    public Hashtable<String,dryStatus> glblDryStatus;
    public enum dryStatus {
        Page_Conflict{
            String text() {return "Conflict: Ambiguous Proteins";}
            int count = 0;
            void setPCount(int x) {
                count = x;
            }
            int getPCount() {
                return count;
            }
        },
        No_Matches{
            String text() {return "Proteins without matches";}
            int count = 0;
            void setPCount(int x) {
                count = x;
            }
            int getPCount() {
                return count;
            }
        },
        Found_Match{
            String text() {return "Proteins with a clean match";}
            int count = 0;
            void setPCount(int x) {
                count = x;
            }
            int getPCount() {
                return count;
            }
        },
        High_Match{
            String text() {return "Proteins with a High Potential Match";}
            int count = 0;
            void setPCount(int x) {
                count = x;
            }
            int getPCount() {
                return count;
            }
        },
        Redirected{
            String text() {return "Redirected Proteins";}
            int count = 0;
            void setPCount(int x) {
                count = x;
            }
            int getPCount() {
                return count;
            }
        };
        
        abstract String text();
        abstract void setPCount(int x);
        abstract int getPCount();
    }
    
    private class Entry {
        
        String title;
        String description;
        Date date;
        logs log;
        
        public Entry(String ti, String des, Date dt, logs l) {
            title = ti;
            description = des;
            date = dt;
            log = l;
        }
        
        public logs getLog(){
            return log;
        }
        
        public Date getDate() {
            return date;
        }
        
        public String getDesc() {
            return description;
        }
        
        public String getTitle() {
            return title;
        }
        
    }
    
    
    String logDirectory;
    File logDirFile;
    private File fSummary;
    private File fError;
    private File fCreated;
    private File fUpdated;
    private File fSkipped;
    private File fSystem;
    private File fRedirect;
    Calendar logTime;
    
    /** Creates a new instance of PBBLogging */
    public PBBLogging(String dir) throws Exception{
        
        logEntries = new TreeMap<String,Vector>();
        glblProteinStatus = new Hashtable<String,pStatus>();
        glblDryStatus = new Hashtable<String,dryStatus>();
        glblProteinTargetPages = new Hashtable<String,String>();
        
        logDirectory = dir;
        //Need to get the logtimes...
        logTime = Calendar.getInstance();
        //Make sure we actually have a directoy...
        logDirFile = new File(logDirectory);
        
        if(logDirFile.exists()) {
            if (!logDirFile.isDirectory()){
                throw new Exception("Log location is not a directory.");
            }
            
        }else {
            if (!logDirFile.mkdirs()) {
                throw new Exception("Cannot create Log Directories.");
            }
            
        }
        
        //Ok, now we make the directory based on the time...
        String base = getDateTimeStamp().replace(':','.');
        //Now make all the log files and make sure they are read/writeable.
        fSummary = new File(logDirFile,"PBB LOG- " + base + "/" + this.SUMMARY);
        fSummary.mkdirs();
        if (!initFile(fSummary)){
            throw new Exception("Cannot write to Summary Log File: " + fSummary.getAbsolutePath());
        }
        fError = new File(logDirFile,"PBB LOG- " + base + "/" + this.ERROR);
        if (!initFile(fError)){
            throw new Exception("Cannot write to Error Log File: " + fError.getAbsolutePath());
        }
        fCreated = new File(logDirFile,"PBB LOG- " + base + "/" + this.CREATED);
        if (!initFile(fCreated)){
            throw new Exception("Cannot write to Created Log File: " + fCreated.getAbsolutePath());
        }
        fUpdated = new File(logDirFile,"PBB LOG- " + base + "/" + this.UPDATED);
        if (!initFile(fUpdated)){
            throw new Exception("Cannot write to Updated Log File: " + fUpdated.getAbsolutePath());
        }
        fSystem = new File(logDirFile,"PBB LOG- " + base + "/" + this.SYSTEM);
        if (!initFile(fSystem)){
            throw new Exception("Cannot write to System Log File: " + fSystem.getAbsolutePath());
        }
        fSkipped = new File(logDirFile,"PBB LOG- " + base + "/" + this.SKIPPED);
        
        if (!initFile(fSkipped)){
            throw new Exception("Cannot write to Skipped Log File: " + fSkipped.getAbsolutePath());
        }
        fRedirect = new File(logDirFile,"PBB LOG- " + base + "/" + this.REDIRECTED);
        
        if (!initFile(fRedirect)){
            throw new Exception("Cannot write to Redirected Log File: " + fRedirect.getAbsolutePath());
        }
        //DEBUG
        //System.out.println("Date: " + getDateStamp());
        //System.out.println("Time: " + getTimeStamp());
        //System.out.println("DateTime: " + getDateTimeStamp());
        
        //now that we have the files, we need writers for them...
        wCreated = new BufferedWriter(new FileWriter(fCreated));
        wError   = new BufferedWriter(new FileWriter(fError));
        wSkipped = new BufferedWriter(new FileWriter(fSkipped));
        wSummary = new BufferedWriter(new FileWriter(fSummary));
        wSystem  = new BufferedWriter(new FileWriter(fSystem));
        wUpdated = new BufferedWriter(new FileWriter(fUpdated));
        wRedirect = new BufferedWriter(new FileWriter(fRedirect));
        logsClosed = false;
        
        //Now write out the HTML headers for the files.
        for (logs log: logs.values()){
            getOutput(log).write(getHTMLHeaders(log.text()));
        }
        
    }
    
    boolean logsClosed;
    public void closeLogs() throws IOException{
        //Used to terminate all logging activities (closes the streams, mainly)
        logsClosed = true;
        for (logs log: logs.values()){
            getOutput(log).flush();
            getOutput(log).close();
        }
        
    }
    
    
    private boolean initFile(File f) throws IOException{
        //Quick method to check the status of a newly created file..
        //makes sure all is well.
        if(f.exists()){
            f.delete();
        }
        f.createNewFile();
        if (!f.canWrite()){
            return false;
        }
        return true;
    }
    
    
    public void addEntry(String name, String title, String info, logs log){
        
        Vector<Entry> tmp;
        if (log == logs.SY) {
            try{//special handling for system messages.
                //We will be writing at the time of the event instead of storing the log
                getOutput(log).write(this.getHTMLEntry(title,info,this.getDateTimeStamp()));
            }catch (Exception e){
                System.out.println("Had exception while outputting to System log: " + e.getMessage());
            }
        }else {
            if (logEntries.containsKey(name)) {
                tmp = logEntries.get(name);
                if (tmp == null){
                    tmp = new Vector<Entry>();
                }
                tmp.add(new Entry(title,info,Calendar.getInstance().getTime(),log));
            } else {
                tmp = new Vector<Entry>();
                tmp.add(new Entry(title,info,Calendar.getInstance().getTime(),log));
                logEntries.put(name,tmp);
            }
        }
        
    }
    /* a Quick little method for dumping extra information into the SYstem log (such as
     * indents)
     */
    public void addSysHTML(String text) throws IOException{
        getOutput(logs.SY).write(text);
    }
    
    //Should change the log enum into the proper output file...
    private File getFile(logs log){
        switch(log){
            case CR: return fCreated;
            case ER: return fError;
            case SK: return fSkipped;
            case SU: return fSummary;
            case SY: return fSystem;
            case UP: return fUpdated;
            case RD: return fRedirect;
        }
        return null;
    }
    
    //Output methods...
    
    BufferedWriter wCreated;
    BufferedWriter wError;
    BufferedWriter wSkipped;
    BufferedWriter wSummary;
    BufferedWriter wSystem;
    BufferedWriter wUpdated;
    BufferedWriter wRedirect;
    
    private BufferedWriter getOutput(logs log) {
        //Should return the writer associated with the log
        switch(log){
            case CR: return wCreated;
            case ER: return wError;
            case SK: return wSkipped;
            case SU: return wSummary;
            case SY: return wSystem;
            case UP: return wUpdated;
            case RD: return wRedirect;
        }
        return null;
    }
    
    public String getWikiLog(Hashtable<String,String> locations) {
        //Goes through and gathers all the information in wiki format then returns it
        //so that it may be uploaded (presumably).
        String lineSep = System.getProperty("line.separator");
        String data = "";
        Set<String> mySet = logEntries.keySet();
        Iterator<String> myIt = mySet.iterator();
        
        
        data = data + "== Vebose Log - Date: ~~~~~ ==" + lineSep;
        while (myIt.hasNext()){
            String name = myIt.next();
            Vector<Entry> events = logEntries.get(name);
            //String title = "<p><big>'''" + name + "'''</big></p>";
            String title = "===" + name + "===";
            //A little header data here before the events are processed...
            if (locations != null){
                if (locations.containsKey(name)){
                    //get the location data for the page.
                    //title = "<p><big>'''[[" + locations.get(name) + "|" + name + "]]'''</big></p>";
                    title = "===[[" + locations.get(name) + "|" + name + "]]===";
                }
            }
            data = data + title + lineSep;
            for (int i = 0; i < events.size(); i++){
                Entry tmp = events.get(i);
                String tmpStr = this.getWikiEntry(tmp);
                if (tmpStr.trim().compareTo("") != 0){
                    data = data + this.getWikiEntry(tmp) + lineSep;
                }
            }
        }
        
        data = data + "end log.";
        
        
        return data;
    }
    
    public String getWikiLogDryStatus() {
        String lineSep = System.getProperty("line.separator");
        String data = "";
        Set<String> mySet = this.glblDryStatus.keySet();
        Iterator<String> myIt = mySet.iterator();
        
        EnumMap<dryStatus,String> sections = new EnumMap<dryStatus,String>(dryStatus.class);
        
        //clear up the strings.
        for (dryStatus ds: dryStatus.values()){
            sections.put(ds,"");
            ds.setPCount(0);
        }
        //data = data + "== Protein Dry Status Log - Date: ~~~~~ ==" + lineSep;
        
        while (myIt.hasNext()){
            String protein = myIt.next();
            String title = protein;
            
            dryStatus ds = glblDryStatus.get(protein);
            if (ds != null){
                String tmpStr = sections.get(ds);
                tmpStr = tmpStr +"| [[" + title + "]] " + lineSep;
                ds.setPCount(ds.getPCount()+1);
                if (ds.getPCount() % 5 == 0 && ds.getPCount() > 0) {
                    tmpStr = tmpStr + "|-" + lineSep;
                }
                
                sections.put(ds,tmpStr);
            }
            
        }
        
        for (dryStatus ds: dryStatus.values()){
            String tmpStr = sections.get(ds);
            if (tmpStr.compareTo("") != 0){
                tmpStr = "====" + ds.text() +" (" + ds.getPCount() + ")====" + lineSep + "{| width = 750px" + lineSep + tmpStr + lineSep + "|}" + lineSep;
                data = data + tmpStr;
            }
            
        }
        return data;
    }
    
    public String getWikiLogStatusGrid(Hashtable<String,String> locations) {
        
        String lineSep = System.getProperty("line.separator");
        
        
        String data = "";
        
        //Build the table and headers..
        data = data + "== Protein Status Grid - Date: ~~~~~ ==" + lineSep;
        data += "{| class=\"wikitable sortable\" " + lineSep;
        data += "|-" + lineSep;
        data += "! HUGO Symbol" + lineSep;
        data += "! Action Summary" + lineSep;
        data += "! Target page(s)" + lineSep;
        data += "! WP Symbol Search" + lineSep;
        
        
        Set<String> mySet = this.glblProteinStatus.keySet();
        Iterator<String> myIt = mySet.iterator();
        
        while (myIt.hasNext()){
            
            
            String protein = myIt.next();
            String pages = "";     
            if (locations != null){
                
                if (locations.containsKey(protein)){
                    //get the location data for the page.
                    pages = "Location: [[" + locations.get(protein) + "]];";
                }
                
                
            }  
            if (this.glblProteinTargetPages.containsKey(protein)) {
                    //only look here if we don't have a location.
                    pages = "Other Pages: " + glblProteinTargetPages.get(protein);
            }
            
            pStatus ps = glblProteinStatus.get(protein);
            String tmpStr = "Error"; //should get overwritten
            if (ps != null){
                tmpStr = ps.text();
            }
            data += "|-" + lineSep; //start a new row in the table.
            data += "| " + protein + lineSep;
            data += "| [[#" +protein + "|" + tmpStr + "]]" + lineSep;
            data += "| " + pages + lineSep;
            data += "| [http://en.wikipedia.org/wiki/Special:Search?ns0=1&search=" + protein +"&fulltext=Search]" + lineSep;
            
        }//end While
        
        //end the table:
        data += "|}" + lineSep;
        
        return data;
    }
    
    public String getWikiQuickLog(Hashtable<String,String> locations) {
        String lineSep = System.getProperty("line.separator");
        String text = "== Protein Status Quick Log - Date: ~~~~~ ==" + lineSep;
        text += this.getWikiLogDryStatus() + lineSep;
        text += this.getWikiLogProteinStatus(locations) + lineSep;
        
        return text;
    }
    
    public String getWikiLogProteinStatus(Hashtable<String,String> locations){
        String lineSep = System.getProperty("line.separator");
        String data = "";
        Set<String> mySet = this.glblProteinStatus.keySet();
        Iterator<String> myIt = mySet.iterator();
        
        EnumMap<pStatus,String> sections = new EnumMap<pStatus,String>(pStatus.class);
        
        //clear up the strings.
        for (pStatus ps: pStatus.values()){
            sections.put(ps,"");
            ps.setPCount(0);
        }
        //data = data + "== Protein Status Log - Date: ~~~~~ ==" + lineSep;
        
        while (myIt.hasNext()){
            String protein = myIt.next();
            String title = protein;
            if (locations != null){
                
                if (locations.containsKey(protein)){
                    //get the location data for the page.
                    title = "[[" + locations.get(protein) + "|" + protein + "]]";
                }
            }
            pStatus ps = glblProteinStatus.get(protein);
            if (ps != null){
                String tmpStr = sections.get(ps);
                tmpStr = tmpStr +"| " + title + " " + lineSep;
                ps.setPCount(ps.getPCount()+1);
                if (ps.getPCount() % 5 == 0 && ps.getPCount() > 0) {
                    tmpStr = tmpStr + "|-" + lineSep;
                }
                
                sections.put(ps,tmpStr);
            }
            
        }
        
        for (pStatus ps: pStatus.values()){
            String tmpStr = sections.get(ps);
            if (tmpStr.compareTo("") != 0){
                tmpStr = "====" + ps.text() + " (" + ps.getPCount() + ")====" + lineSep + "{| width = 750px" + lineSep + tmpStr + lineSep + "|}" + lineSep;
                data = data + tmpStr;
            }
            
        }
        return data;
    }
    
    public String getWikiLogCondensed(Hashtable<String,String> locations){
        String lineSep = System.getProperty("line.separator");
        String data = "";
        Set<String> mySet = logEntries.keySet();
        Iterator<String> myIt = mySet.iterator();
        
        EnumMap<logs,Boolean> written = new EnumMap<logs,Boolean>(logs.class);
        
        EnumMap<logs,String> sections = new EnumMap<logs,String>(logs.class);
        for (logs log: logs.values()){
            written.put(log,new Boolean("false"));
            sections.put(log,""); //====" + log.text() + "====" + lineSep);
            log.setPCount(0);
        }
        //Cheating a little here - we'll
        //String[] sections = new String[4]
        
        data = data + "== Condensed Log - Date: ~~~~~ ==" + lineSep;
        //need to sort up by entry instead of by protein.
        while (myIt.hasNext()){
            String name = myIt.next();
            Vector<Entry> events = logEntries.get(name);
            String title = name;
            if (locations != null){
                
                if (locations.containsKey(name)){
                    //get the location data for the page.
                    title = "[[" + locations.get(name) + "|" + name + "]]";
                }
            }
            for (int i = 0; i < events.size(); i++){
                
                Entry tmp = events.get(i);
                if (written.get(tmp.getLog()).booleanValue() == false){
                    //Need to write out the protein for this section.
                    String tmpStr = sections.get(tmp.getLog());
                    tmpStr = tmpStr +"| " + title + " " + lineSep;
                    tmp.getLog().setPCount(tmp.getLog().getPCount() + 1);
                    if (tmp.getLog().getPCount() % 5 == 0 && tmp.getLog().getPCount() > 0) {
                        tmpStr = tmpStr + "|-" + lineSep;
                    }
                    
                    sections.put(tmp.getLog(),tmpStr);
                    written.put(tmp.getLog(),new Boolean("true"));
                }
            }
            //now clear the booleans for the next entry.
            for(logs log: logs.values()){
                if(written.get(log).booleanValue() == true){
                    
                    written.put(log,new Boolean("false"));
                    
                }
            }
            
        }
        //Now check and see if there are any entries in a particular section...
        for (logs log: logs.values()){
            String tmpStr = sections.get(log);
            if (tmpStr.compareTo("") != 0){
                tmpStr = "====" + log.text() +" (" + log.getPCount() + ")====" + lineSep + "{| width = 750px" + lineSep + tmpStr + lineSep + "|}" + lineSep;
                data = data + tmpStr;
            }
            
        }
        
        return data;
    }
    
    public void outputLogs(Hashtable<String,String> locations){
        //Going to dump the log files...
        if (!logsClosed){
            //First the HTML
            try {
                outputHTMLLogs(locations);
            } catch( IOException ioe) {
                System.out.println("IO Error while outputting HTML log files...");
                ioe.printStackTrace();
            } catch(Exception e) {
                System.out.println("Other Error while outputting HTML log files...");
                e.printStackTrace();
            }
        }else {
            System.out.println("Cannot output to log files after they have been closed.");
        }
        
    }
    
    public String getHTMLEntry(String title, String info, String stamp){
        if (title.compareTo("BLOCK") == 0){
            //Got a special "Block Code" entry.  We need to display this differently.
            return "<blockquote><pre> " + info + " </pre></blockquote>";
        } else if (title.indexOf("WP:") == -1){
            return "<li><b>"+ title+ "</b>: " + info + "<I><font size=-2> {" + stamp + "} </font></i> </li>";
            
        }
        return "";
    }
    
    private String getWikiEntry(Entry entry){
        //Check for a HTML ONLY (Denoted with HTML:) entry and skip it.
        if (entry.getTitle().compareTo("BLOCK") == 0){
            //Got a special "Block Code" entry.  We need to display this differently.
            return "<pre><nowiki> " + entry.getDesc() + " </nowiki></pre>";
        } else if (entry.getTitle().indexOf("HTML:") == -1){
            int tmp = entry.getTitle().indexOf("WP:");
            String title;
            if (tmp != -1) {
                title = entry.getTitle().substring(tmp + 3);
            } else {
                title = entry.getTitle();
            }
            return "* '''" + title + "''': " + entry.getDesc() + "''<small> {" + this.getDateTimeStamp(entry.getDate()) + "} </small>''";
        }
        return "";
    }
    
    private String getHTMLEntry(Entry entry){
        //Check for a Wikipedia ONLY (Denoted with WP:) entry and skip it.
        if (entry.getTitle().compareTo("BLOCK") == 0){
            //Got a special "Block Code" entry.  We need to display this differently.
            return "<blockquote><pre> " + entry.getDesc() + " </pre></blockquote>";
        } else if (entry.getTitle().indexOf("WP:") == -1){
            int tmp = entry.getTitle().indexOf("HTML:");
            String title;
            if (tmp != -1) {
                title = entry.getTitle().substring(tmp + 5);
            } else {
                title = entry.getTitle();
            }
            
            return "<li><b>"+ title+ "</b>: " + entry.getDesc() + "<I><font size=-2> {" + this.getDateTimeStamp(entry.getDate()) + "} </font></i> </li>";
        }
        return "";
    }
    
    public String getHTMLEntryBR(String title, String info, String stamp){
        if (title.compareTo("BLOCK") == 0){
            //Got a special "Block Code" entry.  We need to display this differently.
            return "<blockquote><pre> " + info + " </pre></blockquote><br>";
        } else if (title.indexOf("WP:") == -1){
            return "<li><b>"+ title+ "</b>: " + info + "<I><font size=-2> {" + stamp + "} </font></i> </li><br>";
        }
        return "";
    }
    public void outputHTMLLogs(Hashtable<String,String> locations) throws IOException{
        //Output the HTML based log to the local machine.
        //No need to start with the headers, they have already been written
        //Start with the headers for each file...
        //for (logs log: logs.values()){
        //    getOutput(log).write(getHTMLHeaders(log.text()));
        //}
        
        //Now we need to pull out the entries and place them into the appropriate log files.
        //we do this based on the name of the protein with the idea being:
        // Protein1
        //  -Event
        //  -Event
        //
        // Protein2
        // ...
        Set<String> mySet = logEntries.keySet();
        Iterator<String> myIt = mySet.iterator();
        EnumMap<logs,Boolean> written = new EnumMap<logs,Boolean>(logs.class);
        for (logs log: logs.values()){
            written.put(log,new Boolean("false"));
        }
        
        while (myIt.hasNext()){
            String name = myIt.next();
            Vector<Entry> events = logEntries.get(name);
            for (int i = 0; i < events.size(); i++){
                Entry tmp = events.get(i);
                if (written.get(tmp.getLog()).booleanValue() == false){
                    //Need to write out the protein header.
                    String title = "<B><Font size=+2>" + name + " - </font></B><ul>";
                    //A little header data here before the events are processed...
                    if (locations != null){
                        if (locations.containsKey(name)){
                            //get the location data for the page.
                            title = "<B><Font size=+2><a href=" + locations.get(name) + ">" + name + " -</a></font></B><ul>";
                        }
                    }
                    this.getOutput(tmp.getLog()).write(title );
                    written.put(tmp.getLog(),new Boolean("true"));
                }
                this.getOutput(tmp.getLog()).write(this.getHTMLEntry(tmp));
            }
            //now clear the booleans for the next entry.
            for(logs log: logs.values()){
                if(written.get(log).booleanValue() == true){
                    this.getOutput(log).write("<br></UL>");
                    
                    written.put(log,new Boolean("false"));
                    
                }
            }
            
        }
        
        String sumInfo = "";
        for (logs log: logs.values()){
            if (log != logs.SU){
                //don't need the summary log file...
                sumInfo = sumInfo + "<a href=" + log.filename() + "> "+ log.text() + "</a><br>";
            }
        }
        this.getOutput(logs.SU).write(sumInfo);
        
        //end with the footers for each file...
        for (logs log: logs.values()){
            getOutput(log).write(getHTMLFooters(log.text()));
        }
        
        
        
    }
    
    private String getHTMLFooters(String name) {
        String lineSep = System.getProperty("line.separator");
        String text = "";
        text =  "</UL><HR SIZE=3 NOSHADE>" + lineSep +
                "<I>Log file, " + name + " automatically generated by Protein Box Bot.</I>" + lineSep +
                "</BODY>" + lineSep +
                "</HTML>" + lineSep;
        
        return text;
    }
    
    private String getHTMLHeaders(String name){
        //Returns a big header for the HTML file.  name is a place holder for the title of the page.
        String lineSep = System.getProperty("line.separator");
        String text = "";
        text =  "<HTML>" + lineSep +
                "<HEAD>" + lineSep +
                "<title>LogFile: " + name + "</title>" + lineSep +
                "</HEAD>" + lineSep +
                "<BODY BGCOLOR=\"#FFFFFF\">" + lineSep +
                "<center> <h1>" + name + "</h1></center>" + lineSep +
                "<hr size=3 noshade>" + lineSep +
                "Logging started:" + this.getDateTimeStamp() + lineSep +
                "<UL>" + lineSep;
        
        return text;
        
    }
    
    public String getDateStamp() {
        logTime = Calendar.getInstance();
        DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM);
        return df.format(logTime.getTime());
    }
    
    public String getDateStamp(Date d) {
        
        DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM);
        return df.format(d);
    }
    
    public String getTimeStamp() {
        logTime = Calendar.getInstance();
        DateFormat df = DateFormat.getTimeInstance(DateFormat.LONG);
        return df.format(logTime.getTime());
        
    }
    
    public String getTimeStamp(Date d) {
        //logTime = Calendar.getInstance();
        DateFormat df = DateFormat.getTimeInstance(DateFormat.LONG);
        return df.format(d);
        
    }
    
    public String getDateTimeStamp() {
        logTime = Calendar.getInstance();
        DateFormat df = DateFormat.getDateTimeInstance(DateFormat.LONG,DateFormat.FULL);
        return df.format(logTime.getTime());
        
    }
    
    public String getDateTimeStamp(Date d) {
        //logTime = Calendar.getInstance();
        DateFormat df = DateFormat.getDateTimeInstance(DateFormat.LONG,DateFormat.FULL);
        return df.format(d);
        
    }
}
